﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SharpSoft.WPF.Controls
{
    /// <summary>
    /// 帧动画控件，主要使用了<see cref="WriteableBitmapExtensions"/>扩展来帮助完成一些位图的处理。
    /// </summary>
    public partial class FrameImagesPlayer : UserControl, IDisposable
    {
        public FrameImagesPlayer()
        {
            InitializeComponent();
            this.Loaded += FrameImagesPlayer_Loaded;
            this.Unloaded += FrameImagesPlayer_Unloaded;
            timer.Tick += Timer_Tick;

        }

        #region EventHandler

        private void Timer_Tick(object sender, EventArgs e)
        {
            if (this.Source == null || this.Source.Length == 0)
            {
                return;
            }
            var index = this.CurrentFrameIndex % this.Source.Length;
            if (index < 0)
            {
                index = this.Source.Length + index;
            }

            if (this.RepeatBehavior.HasDuration)
            {//指定了播放时长
                if (this.stopwatch.Elapsed >= this.RepeatBehavior.Duration)
                {//已到达指定的播放时长
                    this.OnCompleted();//通知播放完毕
                    return;
                }
            }

            if (this.Bitmap == null)
            {
                this.Bitmap = this.Source[0].Clone();
            }
            this.Bitmap.BlitRender(this.Source[index], true, 1);//渲染当前帧
            this.img.InvalidateVisual();
            this.CurrentFrameIndexChanged?.Invoke(this, EventArgs.Empty);//通知帧索引已变化

            if (this.CurrentFrameIndex == this.Source.Length - 1)
            {//这是最后一帧，通知一轮播放完毕
                this.roundCount++;
                this.RoundCompleted?.Invoke(this, EventArgs.Empty);
                if (this.RepeatBehavior.HasCount)
                {//指定了重复播放的次数
                    if (this.roundCount >= this.RepeatBehavior.Count)
                    {//已播放完指定的次数
                        this.OnCompleted();
                        return;
                    }
                }
            }
            this.CurrentFrameIndex = (index + 1) % this.Source.Length;

        }

        private void FrameImagesPlayer_Unloaded(object sender, RoutedEventArgs e)
        {
            this.Pause();
        }

        private void FrameImagesPlayer_Loaded(object sender, RoutedEventArgs e)
        {
            if (this.AutoPlayOnLoaded)
            {
                this.Play();
            }

        }
        #endregion

        private System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer();
        private System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
        private int roundCount = 0;//记录已播放了多少轮

        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);
            if (e.Property == FramerateProperty)
            {
                timer.Interval = TimeSpan.FromSeconds(1) / this.Framerate;
            }
            else if (e.Property == SourceProperty)
            {
                this.RenderCurrentFrame();
            }
        }
        #region 控制

        /// <summary>
        /// 渲染当前帧
        /// </summary>
        public void RenderCurrentFrame()
        {
            if (this.Source == null || this.Source.Length == 0)
            {
                return;
            }
            var index = this.CurrentFrameIndex % this.Source.Length;
            if (index < 0)
            {
                index = this.Source.Length + index;
            }
            if (this.Bitmap == null)
            {
                this.Bitmap = this.Source[0].Clone();
            }
            this.Bitmap.BlitRender(this.Source[index], true, 1);
            this.img.InvalidateVisual();

        }

        /// <summary>
        /// 开始播放
        /// </summary>
        public void Play()
        {
            stopwatch.Start();
            timer.Start();
        }
        /// <summary>
        /// 停止播放
        /// </summary>
        public void Stop()
        {
            this.OnCompleted();
            this.CurrentFrameIndex = 0;//主动调用停止，始终重置帧索引
        }
        /// <summary>
        /// 暂停播放
        /// </summary>
        public void Pause()
        {
            stopwatch.Stop();
            timer.Stop();
        }
        #endregion
        /// <summary>
        /// 设置播放源为系统文件夹内的图片
        /// </summary>
        /// <param name="folderFullPath">文件夹绝对路径</param>
        /// <param name="seachPattern">用于搜索需要的文件，默认为搜索png类型图片</param>
        public async Task SetSourceFolder(string folderFullPath, string seachPattern = "*.png")
        {
            var files = System.IO.Directory.GetFiles(folderFullPath, seachPattern);
            List<Bitmap> list = new List<Bitmap>(files.Length);
            List<WriteableBitmap> bmps = new List<WriteableBitmap>(list.Count);
            await Task.Run(delegate
            {//异步读取文件数据到内存流
                foreach (var item in files)
                {
                    var img = System.Drawing.Image.FromFile(item, true);
                    Bitmap bmp = new Bitmap(img);
                    list.Add(bmp);

                }
            });
            foreach (var bmp in list)
            {
                using (bmp)
                {
                    var wb = BitmapFactory.New(bmp.Width, bmp.Height);
                    wb.Blit(bmp, System.Drawing.Imaging.PixelFormat.Format64bppPArgb);
                    bmps.Add(wb);
                }
            }

            this.Source = bmps.ToArray();
        }
        /// <summary>
        /// 设置设置播放源为资源文件目录内的文件
        /// </summary>
        /// <param name="assembly"></param>
        /// <param name="folder"></param>
        /// <returns></returns>
        public async Task SetSourceResourceFolder(Assembly assembly, string folder)
        {
            var allresnames = assembly.GetManifestResourceNames();
            List<Bitmap> list = new List<Bitmap>();
            await Task.Run(delegate
             {
                 Dictionary<string, Stream> dic = new Dictionary<string, Stream>();

                 foreach (string name in allresnames)
                 {
                     Stream st = assembly.GetManifestResourceStream(name);
                     try
                     {
                         using (ResourceReader resourceReader = new ResourceReader(st))
                         {
                             foreach (DictionaryEntry resourceEntry in resourceReader)
                             {
                                 if (resourceEntry.Key is string relpath)
                                 {
                                     if (resourceEntry.Value is Stream stream)
                                     {
                                         var f = System.IO.Path.GetDirectoryName(relpath).Replace("\\", "/");
                                         Uri u1 = new Uri(f, UriKind.Relative);
                                         var u2 = new Uri(folder, UriKind.Relative);
                                         if (Uri.Compare(u1, u2, UriComponents.Path, UriFormat.UriEscaped, StringComparison.OrdinalIgnoreCase) == 0)
                                         {
                                             dic.Add(relpath, stream);
                                         }
                                     }
                                 }
                             }
                         }
                     }
                     catch (ArgumentException)
                     {
                         throw new Exception("读取资源文件出错。");
                     }
                 }
                 string[] keys = new string[dic.Count];
                 dic.Keys.Each((i, s) =>
                 {
                     keys[i] = s;
                 });
                 Array.Sort(keys);
                 foreach (var item in keys)
                 {
                     var img = System.Drawing.Image.FromStream(dic[item], true);
                     Bitmap bmp = new Bitmap(img);
                     list.Add(bmp);
                 }
             });
            List<WriteableBitmap> bmps = new List<WriteableBitmap>(list.Count);
            foreach (var bmp in list)
            {
                using (bmp)
                {
                    var wb = BitmapFactory.New(bmp.Width, bmp.Height);
                    wb.Blit(bmp, System.Drawing.Imaging.PixelFormat.Format64bppPArgb);
                    bmps.Add(wb);
                }
            }

            this.Source = bmps.ToArray();
        }

        /// <summary>
        /// 获取或设置帧动画的重复播放行为（可以指定次数/时常/永远循环）
        /// </summary>
        public RepeatBehavior RepeatBehavior
        {
            get { return (RepeatBehavior)GetValue(RepeatBehaviorProperty); }
            set { SetValue(RepeatBehaviorProperty, value); }
        }

        public static readonly DependencyProperty RepeatBehaviorProperty =
            DependencyProperty.Register("RepeatBehavior", typeof(RepeatBehavior), typeof(FrameImagesPlayer), new PropertyMetadata(RepeatBehavior.Forever));


        /// <summary>
        /// 播放完成时的行为，是恢复到初始状态还是停留在最后一帧。
        /// </summary>
        public FillBehavior FillBehavior
        {
            get { return (FillBehavior)GetValue(FillBehaviorProperty); }
            set { SetValue(FillBehaviorProperty, value); }
        }

        public static readonly DependencyProperty FillBehaviorProperty =
            DependencyProperty.Register("FillBehavior", typeof(FillBehavior), typeof(FrameImagesPlayer), new PropertyMetadata(FillBehavior.Stop));



        /// <summary>
        /// 获取或设置在资源加载完成后是否自动开始播放
        /// </summary>
        public bool AutoPlayOnLoaded
        {
            get { return (bool)GetValue(AutoPlayOnLoadedProperty); }
            set { SetValue(AutoPlayOnLoadedProperty, value); }
        }

        public static readonly DependencyProperty AutoPlayOnLoadedProperty =
            DependencyProperty.Register("AutoPlayOnLoaded", typeof(bool), typeof(FrameImagesPlayer), new PropertyMetadata(true));



        /// <summary>
        /// 帧率（每秒切换的帧数，默认为24.）
        /// </summary>
        public int Framerate
        {
            get { return (int)GetValue(FramerateProperty); }
            set { SetValue(FramerateProperty, value); }
        }

        public static readonly DependencyProperty FramerateProperty =
            DependencyProperty.Register("Framerate", typeof(int), typeof(FrameImagesPlayer), new PropertyMetadata(24));

        /// <summary>
        /// 在帧动画完成后是否保留当前图像,默认为保留。
        /// </summary>
        public bool KeepImageWhenCompleted { get; set; } = true;

        /// <summary>
        /// 获取或设置帧动画的所有帧图片
        /// </summary>
        public WriteableBitmap[] Source
        {
            get { return (WriteableBitmap[])GetValue(SourceProperty); }
            set { SetValue(SourceProperty, value); }
        }

        public static readonly DependencyProperty SourceProperty =
            DependencyProperty.Register("Source", typeof(WriteableBitmap[]), typeof(FrameImagesPlayer), new PropertyMetadata(null));


        /// <summary>
        /// 当前帧显示的图片
        /// </summary>
        public WriteableBitmap Bitmap
        {
            get { return (WriteableBitmap)GetValue(BitmapProperty); }
            private set { SetValue(BitmapProperty, value); }
        }

        public static readonly DependencyProperty BitmapProperty =
            DependencyProperty.Register("Bitmap", typeof(WriteableBitmap), typeof(FrameImagesPlayer), new PropertyMetadata(null));


        /// <summary>
        /// 获取或设置当前帧索引
        /// </summary>
        public int CurrentFrameIndex
        {
            get { return (int)GetValue(CurrentFrameIndexProperty); }
            set { SetValue(CurrentFrameIndexProperty, value); }
        }

        public static readonly DependencyProperty CurrentFrameIndexProperty =
            DependencyProperty.Register("CurrentFrameIndex", typeof(int), typeof(FrameImagesPlayer), new PropertyMetadata(0));


        /// <summary>
        /// 获取或设置所有帧图片的拉伸方式，默认为“填充”
        /// </summary>
        public Stretch Stretch
        {
            get { return (Stretch)GetValue(StretchProperty); }
            set { SetValue(StretchProperty, value); }
        }

        public static readonly DependencyProperty StretchProperty =
            DependencyProperty.Register("Stretch", typeof(Stretch), typeof(FrameImagesPlayer), new PropertyMetadata(Stretch.Fill));


        /// <summary>
        /// 设置拉伸方向，默认为“水平与垂直均拉伸”
        /// </summary>
        public StretchDirection StretchDirection
        {
            get { return (StretchDirection)GetValue(StretchDirectionProperty); }
            set { SetValue(StretchDirectionProperty, value); }
        }

        public static readonly DependencyProperty StretchDirectionProperty =
            DependencyProperty.Register("StretchDirection", typeof(StretchDirection), typeof(FrameImagesPlayer), new PropertyMetadata(StretchDirection.Both));




        /// <summary>
        /// 在当前帧索引改变时触发
        /// </summary>
        public event EventHandler CurrentFrameIndexChanged;
        /// <summary>
        /// 在播放完成/停止后触发
        /// </summary>
        public event EventHandler RoundCompleted;
        public event EventHandler Completed;

        /// <summary>
        /// 在播放完成时调用，该操作会通知动画并触发<see cref="Completed"/>事件。
        /// </summary>
        protected void OnCompleted()
        {
            stopwatch.Reset();
            timer.Stop();
            this.roundCount = 0;//重置次数计数器
            if (this.FillBehavior == FillBehavior.Stop)
            {
                this.CurrentFrameIndex = 0;
            }
            if (!this.KeepImageWhenCompleted)
            {
                this.Bitmap?.Clear(Colors.Transparent);
            }
            this.Completed?.Invoke(this, EventArgs.Empty);
        }
        /// <summary>
        /// 清空当前显示的位图
        /// </summary>
        public void ClearBitmap()
        {
            this.Bitmap = null;
        }

        public void Dispose()
        {
            this.Bitmap = null;
            this.Source = null;
        }
    }
}
